/* Copyright 2008 Bas van den Berg
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "MudDoor.h"
#include "MudKey.h"
#include "MudPlayer.h"
#include "CmdVisitor.h"
#include "Room.h"
#include "Global.h"
#include "TaskQueue.h"
#include "MudObjectTask.h"
#include "myassert.h"

using namespace Chronos;
using namespace std;

// ------------ MudDoor ------------

MudDoor::MudDoor(const string& name_
			, const string& descr_
			, Portal* portal_
			, unsigned int closeDelay_)
    : MudExit(name_, descr_, portal_)
    , MudOpenable()
	, changed(false)
	, closeDelay(closeDelay_)
{
    ASSERT_NOT_EQUAL(0, closeDelay);
    MudDoor::generateDescription();
}


VISITOR_ACCEPT(MudDoor)


const string& MudDoor::getDescription() const {
    return customDescription;
}


void MudDoor::pass(MudPlayer& player) {
	if (!isOpen) {
		player.write("The " + getName() + " is closed.\n");	
		return;
	}
	MudExit::pass(player);
}


void MudDoor::generateDescription() {
    customDescription = descr;
    if (isOpen) customDescription += " It's open.";
    else customDescription += " It's closed.";
}


void MudDoor::open(MudPlayer& player) {
	if (isOpen) {
		player.write("The " + getName() + " is already open.\n");	
		return;
	}
    if (!canOpen(player)) return;

	isOpen = true;
    generateDescription();
	if (!changed) {
        Global<TaskQueue>()->addTask(new MudObjectFuncTask<MudDoor>(*this, &MudDoor::reset), closeDelay);
		changed = true;
	}
	player.write("OK\n");
	player.getRoom()->showText(player.getName() + " opens the " + getName() + ".", player);
}


void MudDoor::close(MudPlayer& player) {
	if (!isOpen) {
		player.write("The " + getName() + " is already closed.\n");	
		return;
	}
	isOpen = false;
    generateDescription();
	player.write("OK\n");
	player.getRoom()->showText(player.getName() + " closes the " + getName() + ".", player);
}


bool MudDoor::canOpen(MudPlayer& player) {
    return !activateTrigger(MUDOPENABLE_TRY_OPEN, (MudMobile*) &player);
}


unsigned int MudDoor::reset() {
    if (isOpen) {
        isOpen = false;	
        generateDescription();
        room->showText("The " + getName() + " closes.");
    }
    changed = false;
    return 0;
}

// ------------ MudLockedDoor ------------

MudLockedDoor::MudLockedDoor(const string& name_
			, const string& descr_
			, Portal* portal_
			, unsigned int closeDelay_)
    : MudDoor(name_, descr_, portal_, closeDelay_)
    , MudLockable()
{
    MudLockedDoor::generateDescription();
}


VISITOR_ACCEPT(MudLockedDoor)


void MudLockedDoor::generateDescription() {
    if (isLocked) customDescription = descr + " It's locked.";
    else MudDoor::generateDescription();
}


void MudLockedDoor::open(MudPlayer& player) {
    if (isLocked) {
		player.write("The " + getName() + " is locked.\n");	
		return;
    }
    MudDoor::open(player);
}


void MudLockedDoor::lock(MudPlayer& player, const MudKey& key) {
	if (isLocked) {
		player.write("It's already locked.\n");	
		return;
	}
    if (isOpen) {
        player.write("You should close it first.\n");
        return;
    }
    if (key.getID() != keyID) {
        player.write("It's not the right key.\n");
        return;
    }
//    if (!canChangeLock(player)) return;

	isLocked = true;
    generateDescription();
	player.write("OK\n");
	player.getRoom()->showText(player.getName() + " locks the " + getName() + ".", player);
}


void MudLockedDoor::unlock(MudPlayer& player, const MudKey& key) {
	if (!isLocked) {
		player.write("It's not locked.\n");	
		return;
	}
    if (key.getID() != keyID) {
        player.write("It's not the right key.\n");
        return;
    }
//    if (!canChangeLock(player)) return;

	isLocked = false;
    generateDescription();
	if (!changed) {
        Global<TaskQueue>()->addTask(new MudObjectFuncTask<MudLockedDoor>(*this, &MudLockedDoor::reset), closeDelay);
		changed = true;
	}
	player.write("OK\n");
	player.getRoom()->showText(player.getName() + " unlocks the " + getName() + ".", player);
}


unsigned int MudLockedDoor::reset() {
    MudDoor::reset();
    if (!isLocked) isLocked = true;

    generateDescription();
    changed = false;
    return 0;
}

